package com.bianmaba.jobs;

import com.bianmaba.beans.datacollection.CollectionTask;
import com.bianmaba.beans.datacollection.TaskInstance;
import com.bianmaba.beans.datacollection.TaskRunLog;
import com.bianmaba.commons.bean.result.OperationResult;
import com.bianmaba.jobs.supports.CollectionRequest;
import com.bianmaba.jobs.supports.CollectionResult;
import com.bianmaba.services.datacollection.ICollectionTaskService;
import com.bianmaba.services.datacollection.ITaskInstanceService;
import com.bianmaba.services.datacollection.ITaskRunLogService;
import com.bianmaba.services.datacollection.TaskRunLogWriter;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;

import java.util.Arrays;
import java.util.Calendar;
import java.util.concurrent.ExecutorService;

public class CollectionJob implements Job {
    private static Logger LOG = LoggerFactory.getLogger(CollectionJob.class);
    @Autowired
    protected ExecutorService executorService;
    @Autowired
    protected RestTemplate restTemplate;
    @Autowired
    protected ICollectionTaskService collectionTaskService;
    @Autowired
    protected ITaskInstanceService taskInstanceService;
    @Autowired
    protected TaskRunLogWriter logWriter;


    protected CollectionTask task;
    protected JobExecutionContext context;


    @Override
    public void execute(JobExecutionContext context) {
        try {
            this.context = context;
            JobDataMap jobDataMap = this.context.getMergedJobDataMap();
            String taskId = jobDataMap.getString(JobParameter.TASK_ID.getName());
            this.task = collectionTaskService.findOne(taskId);

            String taskInstanceId = context.getMergedJobDataMap().getString(JobParameter.TASK_INSTANCE_ID.getName());
            boolean sended = sendCollectionRequest(taskInstanceId);
            if (sended) {
                checkStatus(taskInstanceId);
            }
        } catch (InterruptedException e) {
            CollectionResult cr = new CollectionResult(TaskInstance.Status.TERMINATED.getIndex(), null);
            context.setResult(cr);
        }
    }

    private void checkStatus(String taskInstanceId) throws InterruptedException {
        while (true) {
            Thread.sleep(1000);
            HttpEntity<String> entity = new HttpEntity(taskInstanceId);
            ResponseEntity<OperationResult> responseEntity = restTemplate.postForEntity(task.getCollectionInterface().getBaseUrl() + "status", entity, OperationResult.class);
            OperationResult<Integer> result = responseEntity.getBody();
            if (result.isSuccess()) {
                Integer status = result.getData();
                taskInstanceService.updateStatus(taskInstanceId, status);
                if (TaskInstance.Status.RUNNING.getIndex() == result.getData().byteValue()) {
                    continue;
                } else if (TaskInstance.Status.SUCCESSFUL.getIndex() == result.getData().byteValue()) {
                    //TODO 任务完成处理结果数据
                }
                break;
            } else {
                //TODO 更新日志
            }
        }
    }

    protected boolean sendCollectionRequest(String taskInstanceId) throws InterruptedException {
        JobDataMap jobDataMap = context.getMergedJobDataMap();
        CollectionRequest requestParameter = new CollectionRequest(jobDataMap);
        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        HttpEntity<CollectionRequest> entity = new HttpEntity(requestParameter, headers);
        String url = this.task.getCollectionInterface().getBaseUrl() + "collection";
        ResponseEntity<OperationResult> responseEntity = null;
        try {
            responseEntity = restTemplate.postForEntity(url, entity, OperationResult.class);
            OperationResult<Boolean> result = responseEntity.getBody();
            logWriter.putLog(TaskRunLog.of(taskInstanceId, result.getResult(), Calendar.getInstance().getTime()));
            if (!result.isSuccess() || !result.getData()) {
                CollectionResult cr = new CollectionResult(TaskInstance.Status.UNSUCCESSFUL.getIndex(), null);
                context.setResult(cr);
                return false;
            }
            return true;
        } catch (HttpClientErrorException e) {
            int code = e.getRawStatusCode();
            String error = e.getLocalizedMessage();
            if (code == 401) {
                error = "采集请求失败，目标地址未经授权访问或由于凭据无效被拒绝：";
            } else if (code == 403) {
                error = "采集请求失败，目标地址未经授权，请联系管理员：";
            } else if (code == 404) {
                error = "采集请求失败，目标地址不存在请联系管理员：";
            } else if (code == 405) {
                error = "采集请求失败，请求方式（Method）不受支持，请联系管理员：";
            } else if (code == 500) {
                error = "采集请求失败，采集服务出现内部错误，请联系管理员：";
            }
            error = error + String.format("【statusCode=%d,URL=%s,parameters=%s】", code, url, requestParameter.toString());
            LOG.error(error, e);
            logWriter.putLog(TaskRunLog.of(taskInstanceId, error, Calendar.getInstance().getTime()));

        } catch (ResourceAccessException e) {
            String error = "采集请求失败，服务器未开启，请联系管理员：";
            error = error + String.format("【URL=%s,parameters=%s】", url, requestParameter.toString());
            LOG.error(error, e);
            logWriter.putLog(TaskRunLog.of(taskInstanceId, error, Calendar.getInstance().getTime()));
        } catch (Exception e) {
            String error = "采集请求失败，采集出现未知异常，请联系管理员：";
            error = error + String.format("【URL=%s,parameters=%s】", url, requestParameter.toString());
            LOG.error(error, e);
            logWriter.putLog(TaskRunLog.of(taskInstanceId, error, Calendar.getInstance().getTime()));
        }
        CollectionResult cr = new CollectionResult(TaskInstance.Status.EXCEPTIONAL.getIndex(), null);
        context.setResult(cr);
        return false;
    }


    //异步处理结果
    class TaskInstanceListener implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                HttpEntity<String> entity = new HttpEntity(context.getMergedJobDataMap().getString(JobParameter.TASK_INSTANCE_ID.getName()));
                ResponseEntity<String> responseEntity = restTemplate.postForEntity(task.getCollectionInterface().getBaseUrl() + "/status", entity, String.class);
                System.out.println(responseEntity);
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            context.setResult(new CollectionResult(TaskInstance.Status.SUCCESSFUL.getIndex(), "测试数据"));
        }
    }

    public static enum JobParameter {
        TASK_INSTANCE_ID("taskInstanceId", 1),
        TASK_ID("taskId", 2),
        DESCRIPTION("description", 3),
        COLLECTION_PARAMETERS("collectionParameters", 4),
        PROJECT_ID("projectId", 5);

        // 成员变量
        private String name;
        private int index;

        // 构造方法
        private JobParameter(String name, int index) {
            this.name = name;
            this.index = index;
        }

        // get set 方法
        public String getName() {
            return name;
        }
    }

}
